初次接触网络编程,作为一个菜鸟也来分享一下心得,希望同为菜鸟的童鞋在看完这篇文章后能后有所收获。
基本的网络编程概念请参考这篇博文:
http://blog.csdn.net/tigerjibo/article/details/6775534
里面详细的介绍了socket编程的步骤和相关函数,弱渣在此就不再重述了。下面请让我来为大家介绍一个简单的tcp网络编程实例吧。
功能介绍:本程序可以实现服务端与多个客户端进行通信,服务端主线程是用来接收来自客户端发过来的数据,而子线程用来给客户端发送数据;同样的道理,客户端则是在主线程里给服务端发送数据,而子线程里则接收服务端发过来的数据。
服务端程序:
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
void *func(void *arg)
{
int st = *(int *) arg;
char buf[1024];
while (1)
{
memset(buf, 0, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
send(st, buf, strlen(buf), 0);
}
return NULL;
}
int main(int arg, char *args[])
{
if (arg < 2)
return 0;
printf("process start\n");
//第一步初始化
int st = socket(AF_INET, SOCK_STREAM, 0);
if (st == -1)
{
printf("socket error is: %s\n", strerror(errno));
return 0;
}
int on = 1;
//让地址可重用
if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
printf("setsockopt failed %s\n", strerror(errno));
return 0;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(args[1]));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//第二步,绑定IP地址和端口号
if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
printf("bind error is: %s\n", strerror(errno));
return 0;
}
//第三步,listen
if (listen(st, 20) == -1)
{
printf("listen error is: %s\n", strerror(errno));
return 0;
}
char buf[1024];
int client_st = 0;
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
socklen_t len = sizeof(client_addr);
//第四步,accept
client_st = accept(st, (struct sockaddr *) &client_addr, &len);
if (client_st == -1)
{
printf("accept error is: %s\n", strerror(errno));
return 0;
}
printf("from %s\n", inet_ntoa(client_addr.sin_addr));
pthread_t thr_d;
pthread_create(&thr_d, NULL, func, &client_st);
while (1)
{
memset(buf, 0, sizeof(buf));
//第五步,接收或发送数据
if (recv(client_st, buf, sizeof(buf), 0) <= 0)
{
printf("recv error is: %s\n", strerror(errno));
close(client_st);
return 0;
}
printf("recv is %s\n", buf);
}
//关闭socket
close(st);
pthread_join(thr_d, NULL);
printf("process end\n");
return 0;
}
客户端程序:
//cleint.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
void *func(void *arg)
{
int st = *(int *) arg;
char buf[1024];
while (1)
{
memset(buf, 0, sizeof(buf));
if (recv(st, buf, sizeof(buf), 0) > 0)
{
printf("%s\n", buf);
} else
{
break;
}
}
return NULL;
}
int main(int arg, char *args[])
{
if (arg < 3)
return 0;
printf("process start\n");
//第一步初始化
int st = socket(AF_INET, SOCK_STREAM, 0);
if (st == -1)
{
printf("socket error is: %s\n", strerror(errno));
return 0;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(args[2]));
addr.sin_addr.s_addr = inet_addr(args[1]);
//第二步,连接到server端
if (connect(st, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
printf("connect error is: %s\n", strerror(errno));
return 0;
}
pthread_t thr_d;
pthread_create(&thr_d, NULL, func, &st);
char buf[1024];
while (1)
{
memset(buf, 0, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
//第三步,接收或者发送数据
if (send(st, buf, strlen(buf), 0) == -1)
{
printf("send error is: %s\n", strerror(errno));
return 0;
}
}
//关闭socket
close(st);
pthread_join(thr_d, NULL);
printf("process end\n");
return 0;
}
现在就来测试一下,上面两个程序我都放在了多线程聊天这个文件夹,并且被两个ubuntu系统所共享,其中ubuntuA作为服务端,另一个ubuntuB作为客户端。首先编译两个c程序,然后在服务端输入./server 8080后回车(第二个参数是服务器监听的端口号),截图如下:
然后在客户端运行./client 192.168.0.102 8080(第二个参数是服务端的ip,第三个是服务端监听的端口号),回车后即可双向通信,并且客户端连上服务端之后,服务端会首先打印客户端的ip,截图如下: