socket网络编程
- 客户端为什么不需要bind?
因为服务器是时时在监听有没有客户端的连接,所以需要绑定IP和端口。而客户端就不需要了,客户端上线是主动向服务器发出请求的,因为服务器已经绑定了IP和端口,所以客户端上线的就向这个IP和端口发出请求,客户端的端口是系统随机分配的。bind()函数和connect()的参数列表很相似,但是第二个参数,bind()的参数为struct sockaddr *my_addr,即为服务端本地的地址,而connect()的第二个参数为struct sockaddr *serv_addr,即为服务器端的地址,所以客户端可以直接向目标服务器发起请求,而目标服务器只需要bind后监听客户端的请求即可。
server.c守护进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <pthread.h>
#include <semaphore.h>
#include <syslog.h>
#define PORT 4321
#define BUFFER_SIZE 10240
#define MAX_QUE_CONN_NM 5
#define MAX_MSG 128
struct Param{
int src_sock, dest_sock, thread_id;
};
pthread_t thread[2];
void *forward(void *arg){
struct Param tmp = *(struct Param*)arg;
char str[MAX_MSG];
int res;
while(1){
res = read(tmp.src_sock, str, MAX_MSG);
if(res == -1){
syslog(LOG_ERR, "read error");
exit(1);
// pthread_exit(NULL);
}
res = write(tmp.dest_sock, str, MAX_MSG);
if(res == -1){
syslog(LOG_ERR, "write error");
exit(1);
// pthread_exit(NULL);
}
if(strcmp(str, "quit") == 0){
pthread_cancel(thread[tmp.thread_id ^ 1]);
pthread_exit(NULL);
}
}
pthread_exit(NULL);
}
void work(){
int serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if(serv_sock == -1){
syslog(LOG_ERR, "%s\n", "socket");
exit(1);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_addr.s_addr = INADDR_ANY;
int res = bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if(res == -1){
syslog(LOG_ERR, "%s\n", "bind");
exit(1);
}
res = listen(serv_sock, MAX_QUE_CONN_NM);
if(res == -1){
syslog(LOG_ERR, "%s\n", "listen");
exit(1);
}
while(1){
struct sockaddr_in clnt_addr1, clnt_addr2;
socklen_t clnt_addr_size1 = sizeof(clnt_addr1), clnt_addr_size2 = sizeof(clnt_addr2);
int clnt_sock1 = accept(serv_sock, (struct sockaddr*)&clnt_addr1, &clnt_addr_size1);
if(clnt_sock1 == -1){
syslog(LOG_ERR, "%s\n", "accept1");
exit(1);
}
int clnt_sock2 = accept(serv_sock, (struct sockaddr*)&clnt_addr2, &clnt_addr_size2);
if(clnt_sock2 == -1){
syslog(LOG_ERR, "%s\n", "accept2");
exit(1);
}
struct Param arg1, arg2;
arg1.src_sock = clnt_sock1;
arg1.dest_sock = clnt_sock2;
arg1.thread_id = 0;
arg2.src_sock = clnt_sock2;
arg2.dest_sock = clnt_sock1;
arg2.thread_id = 1;
res = pthread_create(&thread[0], NULL, forward, &arg1);
if(res != 0){
syslog(LOG_ERR, "thread create failed, ERROR NUMBER:%d\n", res);
exit(1);
}
res = pthread_create(&thread[1], NULL, forward, &arg2);
if(res != 0){
syslog(LOG_ERR, "thread create failed, ERROR NUMBER:%d\n", res);
exit(1);
}
void * thrd_ret;
res = pthread_join(thread[0], &thrd_ret);
if(res != 0){
syslog(LOG_ERR, "thread join failed, ERROR NUMBER:%d\n", res);
exit(1);
}
res = pthread_join(thread[1], &thrd_ret);
if(res != 0){
syslog(LOG_ERR, "thread join failed, ERROR NUMBER:%d\n", res);
exit(1);
}
close(clnt_sock1);
close(clnt_sock2);
}
close(serv_sock);
}
int main(){
pid_t pid, sid;
int i, fd;
pid = fork();
if (pid < 0){
printf("Error fork\n");
exit(1);
}
else if (pid > 0){
exit(0);
}
openlog("daemon_syslog", LOG_PID, LOG_DAEMON);
if(sid = setsid() < 0){
syslog(LOG_ERR, "%s\n", "setsid");
exit(1);
}
if(sid = chdir("/") < 0){
syslog(LOG_ERR, "%s\n", "chdir");
exit(1);
}
umask(0);
for(i = 0; i < getdtablesize(); i++){ //getdtablesize()返回所在进程的文件描述符表的项数
close(i);
}
/**** do something ****/
work();
/***********************/
closelog();
exit(0);
}
client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <semaphore.h>
#define PORT 4321
#define MAX_MSG 128
#define BUFFER_SIZE 1024
struct Param{
int sock;
};
pthread_t send_thread, recv_thread;
void *send_func(void *arg){
struct Param tmp = *(struct Param*)arg;
char buf[BUFFER_SIZE];
while(1){
memset(buf, 0, MAX_MSG);
printf("Please input(No more than 128 bytes and input \"quit\" to quit):\n");
gets(buf);
int res = write(tmp.sock, buf, MAX_MSG);
if(res == -1){
// pthread_cancel(recv_thread);
// pthread_exit(NULL);
perror("send thread error");
exit(1);
}
if(strcmp(buf, "quit") == 0){
pthread_cancel(recv_thread);
pthread_exit(NULL);
}
}
pthread_exit(NULL);
}
void *recv_func(void *arg){
struct Param tmp = *(struct Param*)arg;
char buf[BUFFER_SIZE];
while(1){
memset(buf, 0, MAX_MSG);
int res = read(tmp.sock, buf, MAX_MSG);
if(res == -1){
// pthread_cancel(send_thread);
perror("recv thread error");
exit(1);
// pthread_exit(NULL);
}
if(strcmp(buf, "quit") == 0){
pthread_cancel(send_thread);
pthread_exit(NULL);
}
puts("receive message:");
puts(buf);
}
pthread_exit(NULL);
}
int main(){
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
//serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_addr.s_addr = INADDR_ANY; //表示本机所有ip
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
int res;
struct Param arg1, arg2;
arg1.sock = sock;
arg2.sock = sock;
res = pthread_create(&send_thread, NULL, send_func, &arg1);
if(res != 0){
fprintf(stderr, "send thread create failed, ERROR NUMBER:%d", res);
exit(1);
}
res = pthread_create(&recv_thread, NULL, recv_func, &arg2);
if(res != 0){
fprintf(stderr, "revc thread create failed, ERROR NUMBER:%d", res);
exit(1);
}
void * thrd_ret;
res = pthread_join(send_thread, &thrd_ret);
if(!res){
printf("send thread joined\n");
}else{
fprintf(stderr, "send thread join failed, ERROR NUMBER:%d", res);
exit(1);
}
res = pthread_join(recv_thread, &thrd_ret);
if(!res){
printf("recv thread joined\n");
}else{
fprintf(stderr, "recv thread join failed, ERROR NUMBER:%d", res);
exit(1);
}
close(sock);
return 0;
}

浙公网安备 33010602011771号